Get single-point-mutation tables (spm_tbl)

Load libraries and functions

library(tidyverse)
library(ggridges)
library(cowplot)
library(bio3d)
library(penm)
library(jefuns)

Initialise

set paths and file names

# file paths and names
spm_path <- "data"
pdb_path <- "data" # pdb files repaired using FoldX (by Elisha)
pdb_prefix <- "RepairPDB_"
run_path <- "output/sc_mut_scan" # directory for this run

Set up parameters

source("set_parameters.R")
# global parameters
beta <- beta_boltzmann()
nmut_per_site <- 19
update_enm <- FALSE # use true to recalculate entropies
add_frust <- FALSE # use true to add frustration terms to energy functions
# other parameters
run_par = lst(
  nmut_per_site = nmut_per_site,
  v0 = 0, # in kcal/mol
  mut_sd_min = 1,
  mut_dl_sigma = .3,
  fit_dg_thr = 0,
  fix_model = "moran",
  fix_n_eff = 1,
  fix_mut_rate = 1,
  beta = beta
)
param <- do.call(set_param, run_par)

# save parameters in run's folder
file_param <- file.path(run_path, "param.rda")
save(beta, nmut_per_site, update_enm, add_frust, run_par, param, file = file_param)

Check input files

#dataset <- tibble(pdb = "1PYL", chain = "A")
dataset <- tibble(pdb = "2ACY", chain = "A")
# read files
dataset <- dataset %>% 
  mutate(wt = map2(pdb,chain, pdb_file_check, 
                   path = pdb_path, prefix = pdb_prefix)) 

# separate info
dataset <- dataset %>% 
  mutate(missing_residues = map_lgl(wt, "missing_residues"),
         n_sites_pdb = map_int(wt, "n_sites"),
         n_unique_resno= map_int(wt, "n_unique_resno"))

# get rid of wt column
dataset <- dataset %>%  dplyr::select(-wt)


# get rid of cases for which there are repeated resno 
dataset <- dataset %>% 
  dplyr::filter(n_sites_pdb == n_unique_resno)

# get rid of cases with "missing residues"
dataset <- dataset %>% 
  dplyr::filter(!missing_residues)

dataset

Set up wild-type

dataset <- dataset %>% 
  mutate(wt = map2(pdb,chain, read_pdb_sc, 
                   path = pdb_path, prefix = pdb_prefix)) %>% 
  filter(!is.na(wt))  

dataset

Get mutants

Initialize wild-type

Check that it works when pdb_active_site is defined

pdb_id <- dataset$pdb
chain <- dataset$chain
wt <- read_pdb_sc(pdb_id, chain, pdb_path, pdb_prefix)
dummy = sample(wt$pdb_site, 1)
dummy = c(dummy - 1, dummy, dummy + 1)
dummy
[1] 78 79 80
wt <- init_prot(wt,  pdb_site_active = dummy, sd_min = param$mut$sd_min)
str(wt)
List of 10
 $ xyz            : num [1:294] 11.81 5.71 -1.69 8.01 9.17 ...
 $ pdb_site       : int [1:98] 1 2 3 4 5 6 7 8 9 10 ...
 $ bfactor        : num [1:98] 79.5 86.9 56.7 83 32.2 ...
 $ nsites         : int 98
 $ site           : int [1:98] 1 2 3 4 5 6 7 8 9 10 ...
 $ pdb_site_active: num [1:3] 78 79 80
 $ site_active    : int [1:3] 78 79 80
 $ ind_active     : num [1:9] 232 233 234 235 236 237 238 239 240
 $ enm            :List of 9
  ..$ graph      : tibble [807 × 8] (S3: tbl_df/tbl/data.frame)
  .. ..$ edge: chr [1:807] "1-2" "1-3" "1-4" "1-5" ...
  .. ..$ i   : int [1:807] 1 1 1 1 1 1 1 1 1 1 ...
  .. ..$ j   : int [1:807] 2 3 4 5 6 7 55 56 58 59 ...
  .. ..$ sdij: int [1:807] 1 2 3 4 5 6 54 55 57 58 ...
  .. ..$ lij : num [1:807] 7.43 9.93 10.44 3.9 9.73 ...
  .. ..$ kij : num [1:807] 189 4.5 4.5 4.5 4.5 4.5 4.5 4.5 4.5 4.5 ...
  .. ..$ dij : num [1:807] 7.43 9.93 10.44 3.9 9.73 ...
  .. ..$ v0ij: num [1:807] 0 0 0 0 0 0 0 0 0 0 ...
  ..$ eij        : num [1:807, 1:3] -0.511 -0.894 -0.921 -0.717 -0.455 ...
  ..$ kmat       : num [1:294, 1:294] 69.4 -44.6 -73.2 -49.4 45 ...
  ..$ mode       : num [1:288] 288 287 286 285 284 283 282 281 280 279 ...
  ..$ evalue     : num [1:288] 613 607 605 596 583 ...
  ..$ cmat       : num [1:294, 1:294] 0.07327 0.00449 0.02325 0.02716 -0.00107 ...
  ..$ umat       : num [1:294, 1:288] 1.02e-05 -2.20e-06 -6.46e-05 -4.08e-06 1.04e-04 ...
  ..$ cmat_active: num [1:9, 1:9] 0.03331 0.00208 0.00524 0.01571 -0.00682 ...
  ..$ kmat_active: num [1:9, 1:9] 142.5 -11.1 -85.2 -125 11.4 ...
 $ energy         :List of 5
  ..$ v_min               : num 0
  ..$ dv_activation       : num 0
  ..$ g_entropy           : num 225
  ..$ g_entropy_activation: num 6.24
  ..$ v_stress            : num 0

Check that it works when pdb_active_site is not defined

pdb_id <- dataset$pdb
chain <- dataset$chain
wt <- read_pdb_sc(pdb_id, chain, pdb_path, pdb_prefix)
wt <- init_prot(wt,  sd_min = param$mut$sd_min)
str(wt)
List of 10
 $ xyz            : num [1:294] 11.81 5.71 -1.69 8.01 9.17 ...
 $ pdb_site       : int [1:98] 1 2 3 4 5 6 7 8 9 10 ...
 $ bfactor        : num [1:98] 79.5 86.9 56.7 83 32.2 ...
 $ nsites         : int 98
 $ site           : int [1:98] 1 2 3 4 5 6 7 8 9 10 ...
 $ pdb_site_active: logi NA
 $ site_active    : logi NA
 $ ind_active     : logi NA
 $ enm            :List of 9
  ..$ graph      : tibble [807 × 8] (S3: tbl_df/tbl/data.frame)
  .. ..$ edge: chr [1:807] "1-2" "1-3" "1-4" "1-5" ...
  .. ..$ i   : int [1:807] 1 1 1 1 1 1 1 1 1 1 ...
  .. ..$ j   : int [1:807] 2 3 4 5 6 7 55 56 58 59 ...
  .. ..$ sdij: int [1:807] 1 2 3 4 5 6 54 55 57 58 ...
  .. ..$ lij : num [1:807] 7.43 9.93 10.44 3.9 9.73 ...
  .. ..$ kij : num [1:807] 189 4.5 4.5 4.5 4.5 4.5 4.5 4.5 4.5 4.5 ...
  .. ..$ dij : num [1:807] 7.43 9.93 10.44 3.9 9.73 ...
  .. ..$ v0ij: num [1:807] 0 0 0 0 0 0 0 0 0 0 ...
  ..$ eij        : num [1:807, 1:3] -0.511 -0.894 -0.921 -0.717 -0.455 ...
  ..$ kmat       : num [1:294, 1:294] 69.4 -44.6 -73.2 -49.4 45 ...
  ..$ mode       : num [1:288] 288 287 286 285 284 283 282 281 280 279 ...
  ..$ evalue     : num [1:288] 613 607 605 596 583 ...
  ..$ cmat       : num [1:294, 1:294] 0.07327 0.00449 0.02325 0.02716 -0.00107 ...
  ..$ umat       : num [1:294, 1:288] 1.02e-05 -2.20e-06 -6.46e-05 -4.08e-06 1.04e-04 ...
  ..$ cmat_active: logi NA
  ..$ kmat_active: logi NA
 $ energy         :List of 5
  ..$ v_min               : num 0
  ..$ dv_activation       : logi NA
  ..$ g_entropy           : num 225
  ..$ g_entropy_activation: logi NA
  ..$ v_stress            : num 0

Plot enm

Plot and compare msf

enm_msf_plot(wt, d_max = param$enm$d_max)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

Plot normal-mode matrix

enm_modes_matrix_plot(wt)

Plot a few normal modes

nsites = wt$nsites
nmodes <- max(wt$enm$mode)
enm_modes_plot(wt, modes = c(1, 2, 3, 4, nmodes - 3, nmodes - 2, nmodes - 1, nmodes))

Mutational change of structure

Get mutants without recalculating ENM

Note that entropy terms do not change w.r.t. wild-type.

get_mut_energy <- function(prot, site, mutation, update_enm, add_frust) {
  mut <- get_mutant_site_2(wt, 
                           site, 
                           mutation, wt, wt,
                           sd_min = param$mut$sd_min,
                           dl_sigma = param$mut$dl_sigma,
                           model = param$enm$model,
                           d_max = param$enm$d_max,
                           v0 = param$enm$v0,
                           add_frust = add_frust,
                           update_enm = update_enm)
  as_tibble(mut$energy)
}

df <- tibble(prot = c("wt", "mut_nofrust", "mut_frust"),
             site = rep(80, 3),
             wt = lst(wt),
             mutation = c(0, 1, 1),
             update_enm = c(F, F, F),
             add_frust = c(F, F, T)) %>% 
  mutate(mut_energy = pmap(list(wt, site, mutation, update_enm, add_frust), get_mut_energy)) %>% 
  unnest(mut_energy) %>% 
  arrange(mutation, add_frust, update_enm) %>% 
  select(-prot, -wt, -mutation) 
New names:
* wt -> wt...1
* wt -> wt...2
* wt -> wt...3
df
NA

Plot structural response

\(f_{ij} = k_{ij} \delta l_{ij}\) is the force in the direction of contact \(i-j\). \(de = K^{1/2} dr = C^{-1/2}df\), \(dr = C df\).

Therefore, in normal-mode representation: \(de_{n} = \sigma_n df_{n}\) and \(dr_n = sigma_n^2 df_n\).

By analogy, in site representation, check if it’s approximately so that \(de^2_{i} = \sigma_n^2 df^2_{i}\) and \(dr^2_i = \sigma_n^4 df^2_i\).

Remember that on average \(df^2_n \propto \frac{1}{\sigma_n^2}\) and probably \(df^2_i \propto 1 / \sigma_i^2\).

Response along sites

mut <- get_mutant_site(wt, 50, mutation = 1)
response_site_plot(wt, mut)
Transformation introduced infinite values in continuous y-axisTransformation introduced infinite values in continuous y-axis`geom_smooth()` using method = 'loess' and formula 'y ~ x'
Removed 3 rows containing non-finite values (stat_smooth).

Response along normal modes

response_nm_plot(wt, mut)
Transformation introduced infinite values in continuous y-axisTransformation introduced infinite values in continuous y-axis`geom_smooth()` using method = 'loess' and formula 'y ~ x'
Removed 3 rows containing non-finite values (stat_smooth).

Perturbation Response Scanning: single-site mutations

# get mutant table
mutation <- seq(from = 0, to = 10)
j <- wt$site

prot_site <- function(prot) prot$site
prot_mode <- function(prot) prot$enm$mode
prot_evalue <- function(prot) prot$enm$evalue


df_mutants <- expand_grid(wt = list(wt), j, mutation)  %>% 
  mutate(mut = pmap(list(wt, j, mutation), get_mutant_site_2)) %>% 
  mutate(i = map(wt, "site"),
         dr2ij = map2(wt, mut, dr2_site),
         msfi = map(wt, msf_prot),
         mode = map(wt, prot_mode),
         evalue = map(wt, prot_evalue),
         dr2nj = map2(wt, mut, dr2_nm)) %>% 
  select(-wt, -mut)

df_j <- tibble(j = wt$site, msfj = msf_prot(wt))
df_mutants <- inner_join(df_j, df_mutants) %>% 
  select(mutation, j, i, msfj, msfi, everything())
Joining, by = "j"
df_mutants 

Structural response along sites

Full mean response matrix:

df_prs_site <- df_mutants %>% 
  select(j, mutation, i, msfj, msfi, dr2ij) %>% 
  unnest(c(i, msfi, dr2ij))

# dr2ij_mean matrix

pij_mean <-  df_prs_site %>% 
  group_by(i, j) %>% 
  summarise(dr2ij_mean = mean(dr2ij),
            dr2ij_sd = sd(dr2ij)) %>% 
  ggplot(aes(j, i, fill = sqrt(dr2ij_mean))) +
  geom_tile() +
  scale_fill_viridis_c() +
  theme_cowplot() +
  NULL +
  theme(legend.position = "none") +
  coord_fixed() +
  ggtitle("sqrt(dr2ij_mean) matrix")

pij_mean



#dr2ij asymmetry
df <- df_prs_site %>% 
  group_by(i, j) %>% 
  summarise(dr2ij_mean = mean(dr2ij))

dr2ij <- df$dr2ij_mean
dim(dr2ij) <- c(length(wt$site), length(wt$site))
str(dr2ij)
 num [1:98, 1:98] 0.02847 0.00691 0.00133 0.0075 0.00472 ...
dr2ji <- t(dr2ij)
df$dr2ji <- as.vector(dr2ji) 

df %>% 
  filter(!(i == j)) %>% 
  ggplot(aes(dr2ij_mean, dr2ji)) +
  geom_point(alpha = .1) +
  theme_cowplot() +
  geom_smooth() +
  scale_x_log10() +
  scale_y_log10() +
  ggtitle("dr2ij is not symmetric")



# dr2ij over single mutation scan, vs. average over several mutation scans
df <- df_prs_site %>% 
  group_by(i, j) %>% 
  summarise(dr2ij_mean = mean(dr2ij))

df <- inner_join(df, df_prs_site)
Joining, by = c("i", "j")
df %>% 
  filter(mutation > 0, mutation < 5) %>% 
  ggplot(aes(dr2ij_mean, dr2ij, color = factor(mutation))) +
  geom_point(size = .2, alpha = .2) +
  geom_smooth(method = "lm") +
  facet_wrap(~mutation) +
  scale_x_log10() +
  scale_y_log10() +
  theme_cowplot() +
  panel_border() +
  ggtitle("dr2ij single scan similar to average over scans")


# dr2ij_sd vs. dr2ij_mean plot

pij <-  df_prs_site %>% 
  group_by(i, j) %>% 
  summarise(dr2ij_mean = mean(dr2ij),
            dr2ij_sd = sd(dr2ij)) %>% 
  ggplot(aes(dr2ij_mean, dr2ij_sd)) +
  geom_point() +
  geom_smooth(method = "lm") +
  geom_abline() +
  theme_cowplot() +
  theme(legend.position = "none") +
  coord_fixed() +
  NULL +
  ggtitle("sd(dr2ij) proportional to mean(dr2ij)")

pij

NA
NA
NA
NA
NA
NA

Response profile vs. site:

# Average response of each site
pi_site <- df_prs_site %>% 
  group_by(i, msfi) %>% 
  summarise(dr2i_mean = mean(dr2ij)) %>% 
  ungroup() %>% 
  ggplot(aes(i, dr2i_mean)) +
  geom_line() +
  theme_cowplot() +
  NULL

pi_msf <- df_prs_site %>% 
  group_by(i, msfi) %>% 
  summarise(dr2i_mean = mean(dr2ij)) %>% 
  ungroup() %>% 
  ggplot(aes(msfi, dr2i_mean)) +
  geom_point() +
  geom_smooth() +
  theme_cowplot() +
  NULL

pi_rmsf <- df_prs_site %>% 
  group_by(i, msfi) %>% 
  summarise(dr2i_mean = mean(dr2ij)) %>% 
  ungroup() %>% 
  ggplot(aes(1 / msfi, dr2i_mean)) +
  geom_point() +
  geom_smooth() +
  theme_cowplot() +
  NULL


plot_grid(pi_site, plot_grid(pi_msf, pi_rmsf), ncol = 1)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

Influence profile (dr2ij averaged over i):

# Average response of each site
pj_site <- df_prs_site %>% 
  group_by(j, msfj) %>% 
  summarise(dr2j_mean = mean(dr2ij)) %>% 
  ungroup() %>% 
  ggplot(aes(j, dr2j_mean)) +
  geom_line() +
  theme_cowplot() +
  NULL

pj_msf <- df_prs_site %>% 
  group_by(j, msfj) %>% 
  summarise(dr2j_mean = mean(dr2ij)) %>% 
  ungroup() %>% 
  ggplot(aes(msfj, dr2j_mean)) +
  geom_point() +
  geom_smooth() +
  theme_cowplot() +
  NULL

pj_rmsf <- df_prs_site %>% 
  group_by(j, msfj) %>% 
  summarise(dr2j_mean = mean(dr2ij)) %>% 
  ungroup() %>% 
  ggplot(aes(1 / msfj, dr2j_mean)) +
  geom_point() +
  geom_smooth() +
  theme_cowplot() +
  NULL



plot_grid(pj_site, plot_grid(pj_msf, pj_rmsf), ncol = 1)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

Structural response along normal modes

df_prs_site <- df_mutants %>% 
  select(j, mutation, i, dr2i) %>% 
  rename(dr2 = dr2i) %>% 
  unnest(i, dr2) 
Error: Can't subset columns that don't exist.
x The column `dr2i` doesn't exist.

Mutational change of ENM

Get mutants recalculating ENM

Now entropy terms should change.

  get_mut <-function(wt, site, mutation = 1, dl_sigma = 1) {
    get_mutant_site_2(wt, 
                           site, 
                           mutation, wt, wt,
                           sd_min = param$mut$sd_min,
                           dl_sigma = dl_sigma,
                           model = param$enm$model,
                           d_max = param$enm$d_max,
                           v0 = param$enm$v0,
                           add_frust = F,
                           update_enm = T)
  } 

mut <- get_mut(wt, 87)

msf_wt <- msf_prot(wt)
msf_mut <- msf_prot(mut)
msf_wt
 [1] 0.19221090 0.22650772 0.27652762 0.23801551 0.15540035 0.11379356 0.08988389 0.08264491 0.08221297 0.09245153
[11] 0.07088199 0.10983968 0.07866147 0.12245703 0.21576473 0.16983013 0.08066221 0.16625006 0.25819479 0.10956434
[21] 0.16064563 0.08016656 0.10045700 0.16565278 0.13648865 0.07399745 0.11437135 0.11827279 0.09858470 0.06925928
[31] 0.13993470 0.16437541 0.10566655 0.17435580 0.06912545 0.08351386 0.08866065 0.10189597 0.07512330 0.11410072
[41] 0.10100282 0.13513072 0.40612314 0.30208413 0.20867748 0.11092580 0.07813797 0.11848193 0.09705542 0.09154759
[51] 0.07543998 0.08182771 0.09289899 0.10136397 0.10067371 0.13664689 0.13084000 0.06887339 0.11194963 0.13527639
[61] 0.08295352 0.09847737 0.13516187 0.08207295 0.07153236 0.17685035 0.21240002 0.15926191 0.08324076 0.10887274
[71] 0.24866472 0.24213216 0.11729905 0.26032454 0.10959876 0.24008642 0.19338515 0.11560144 0.15058885 0.11115986
[81] 0.30865100 0.27992135 0.15388853 0.24487682 0.16795407 0.11886896 0.47436236 0.57496157 0.13781438 0.16247234
[91] 0.13287431 0.23750172 0.21078605 0.07891333 0.10806600 0.11934879 0.13205554 0.24254646
df <- tibble(site = wt$site, wt_msf = msf_wt, mut_msf = msf_mut) 

df %>% 
  mutate(min_msf = map2_dbl(wt_msf, mut_msf, min),
         max_msf = map2_dbl(wt_msf, mut_msf, max)) %>% 
  mutate(min_msf = wt_msf,
         max_msf = mut_msf) %>% 
  pivot_longer(cols = c("wt_msf", "mut_msf"),
               names_to = "protein",
               values_to = "msf") %>% 
  ggplot(aes(site, msf, color = protein)) +
  geom_line() +
  geom_ribbon(aes(ymin = min_msf, ymax = max_msf), alpha = 1, color = NA, fill = "pink") +
  scale_color_viridis_d() +
  theme_cowplot() +
  NULL


df %>% 
  ggplot(aes(site, (msf_mut - msf_wt)/msf_wt)) +
  geom_line() +
  theme_cowplot()

NA
NA
get_mut_energy <- function(site, mutation, wt,...) {
  # gets mutant, returns only its energy terms
  mut <- get_mutant_site(wt, site, mutation,... )
  mut$energy
}

# set up site-mutant table
  spm_tbl <- spm_tbl %>% 
    unnest(site, pdb_site, cn, wcn, bfactor, bfactor_enm, d_active, .drop = TRUE) %>%
    mutate(mutation = replicate(n(), c(0:nmut_per_site), simplify = FALSE)) %>%
    unnest(mutation, .drop = TRUE)
  
  # get mutants
  spm_tbl <- spm_tbl %>% 
    mutate( 
      wt_energy = map(site, ~ wt_energy),
      mut_energy = map2(site, mutation, get_mut_energy,  
                        wt = wt, 
                        sd_min = param$mut$sd_min,
                        update_enm = update_enm, 
                        add_frust = add_frust)) 
  
  # prepare for output
  spm_tbl <- spm_tbl %>% 
    rename(wt = wt_energy, mut = mut_energy) %>% 
    mutate(wt = map(wt, as_tibble), 
           mut = map(mut, as_tibble)) %>% 
    unnest(wt, mut, .sep = "_") 
  
  # output
  pdb <- spm_tbl$pdb[[1]]
  chain <- spm_tbl$chain[[1]]
  out_file <- file.path(run_path,paste0("spm_",pdb, "_", chain, ".csv.gz"))
  write.csv(spm_tbl, file = gzfile(out_file),row.names = FALSE)
LS0tCnRpdGxlOiAiU2NhbiBtdXRhdGlvbnMiIApvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpHZXQgc2luZ2xlLXBvaW50LW11dGF0aW9uIHRhYmxlcyAoc3BtX3RibCkKCiMgTG9hZCBsaWJyYXJpZXMgYW5kIGZ1bmN0aW9ucwoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncmlkZ2VzKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkoYmlvM2QpCmxpYnJhcnkocGVubSkKbGlicmFyeShqZWZ1bnMpCmBgYAoKIyBJbml0aWFsaXNlCiMjIHNldCBwYXRocyBhbmQgZmlsZSBuYW1lcwoKYGBge3J9CiMgZmlsZSBwYXRocyBhbmQgbmFtZXMKc3BtX3BhdGggPC0gImRhdGEiCnBkYl9wYXRoIDwtICJkYXRhIiAjIHBkYiBmaWxlcyByZXBhaXJlZCB1c2luZyBGb2xkWCAoYnkgRWxpc2hhKQpwZGJfcHJlZml4IDwtICJSZXBhaXJQREJfIgpydW5fcGF0aCA8LSAib3V0cHV0L3NjX211dF9zY2FuIiAjIGRpcmVjdG9yeSBmb3IgdGhpcyBydW4KYGBgCgojIyBTZXQgdXAgcGFyYW1ldGVycwoKYGBge3J9CnNvdXJjZSgic2V0X3BhcmFtZXRlcnMuUiIpCiMgZ2xvYmFsIHBhcmFtZXRlcnMKYmV0YSA8LSBiZXRhX2JvbHR6bWFubigpCm5tdXRfcGVyX3NpdGUgPC0gMTkKdXBkYXRlX2VubSA8LSBGQUxTRSAjIHVzZSB0cnVlIHRvIHJlY2FsY3VsYXRlIGVudHJvcGllcwphZGRfZnJ1c3QgPC0gRkFMU0UgIyB1c2UgdHJ1ZSB0byBhZGQgZnJ1c3RyYXRpb24gdGVybXMgdG8gZW5lcmd5IGZ1bmN0aW9ucwojIG90aGVyIHBhcmFtZXRlcnMKcnVuX3BhciA9IGxzdCgKICBubXV0X3Blcl9zaXRlID0gbm11dF9wZXJfc2l0ZSwKICB2MCA9IDAsICMgaW4ga2NhbC9tb2wKICBtdXRfc2RfbWluID0gMSwKICBtdXRfZGxfc2lnbWEgPSAuMywKICBmaXRfZGdfdGhyID0gMCwKICBmaXhfbW9kZWwgPSAibW9yYW4iLAogIGZpeF9uX2VmZiA9IDEsCiAgZml4X211dF9yYXRlID0gMSwKICBiZXRhID0gYmV0YQopCnBhcmFtIDwtIGRvLmNhbGwoc2V0X3BhcmFtLCBydW5fcGFyKQoKIyBzYXZlIHBhcmFtZXRlcnMgaW4gcnVuJ3MgZm9sZGVyCmZpbGVfcGFyYW0gPC0gZmlsZS5wYXRoKHJ1bl9wYXRoLCAicGFyYW0ucmRhIikKc2F2ZShiZXRhLCBubXV0X3Blcl9zaXRlLCB1cGRhdGVfZW5tLCBhZGRfZnJ1c3QsIHJ1bl9wYXIsIHBhcmFtLCBmaWxlID0gZmlsZV9wYXJhbSkKYGBgCgoKCiMgQ2hlY2sgaW5wdXQgZmlsZXMKYGBge3J9CiNkYXRhc2V0IDwtIHRpYmJsZShwZGIgPSAiMVBZTCIsIGNoYWluID0gIkEiKQpkYXRhc2V0IDwtIHRpYmJsZShwZGIgPSAiMkFDWSIsIGNoYWluID0gIkEiKQojIHJlYWQgZmlsZXMKZGF0YXNldCA8LSBkYXRhc2V0ICU+JSAKICBtdXRhdGUod3QgPSBtYXAyKHBkYixjaGFpbiwgcGRiX2ZpbGVfY2hlY2ssIAogICAgICAgICAgICAgICAgICAgcGF0aCA9IHBkYl9wYXRoLCBwcmVmaXggPSBwZGJfcHJlZml4KSkgCgojIHNlcGFyYXRlIGluZm8KZGF0YXNldCA8LSBkYXRhc2V0ICU+JSAKICBtdXRhdGUobWlzc2luZ19yZXNpZHVlcyA9IG1hcF9sZ2wod3QsICJtaXNzaW5nX3Jlc2lkdWVzIiksCiAgICAgICAgIG5fc2l0ZXNfcGRiID0gbWFwX2ludCh3dCwgIm5fc2l0ZXMiKSwKICAgICAgICAgbl91bmlxdWVfcmVzbm89IG1hcF9pbnQod3QsICJuX3VuaXF1ZV9yZXNubyIpKQoKIyBnZXQgcmlkIG9mIHd0IGNvbHVtbgpkYXRhc2V0IDwtIGRhdGFzZXQgJT4lICBkcGx5cjo6c2VsZWN0KC13dCkKCgojIGdldCByaWQgb2YgY2FzZXMgZm9yIHdoaWNoIHRoZXJlIGFyZSByZXBlYXRlZCByZXNubyAKZGF0YXNldCA8LSBkYXRhc2V0ICU+JSAKICBkcGx5cjo6ZmlsdGVyKG5fc2l0ZXNfcGRiID09IG5fdW5pcXVlX3Jlc25vKQoKIyBnZXQgcmlkIG9mIGNhc2VzIHdpdGggIm1pc3NpbmcgcmVzaWR1ZXMiCmRhdGFzZXQgPC0gZGF0YXNldCAlPiUgCiAgZHBseXI6OmZpbHRlcighbWlzc2luZ19yZXNpZHVlcykKCmRhdGFzZXQKYGBgCgoKIyBTZXQgdXAgd2lsZC10eXBlCgpgYGB7cn0KZGF0YXNldCA8LSBkYXRhc2V0ICU+JSAKICBtdXRhdGUod3QgPSBtYXAyKHBkYixjaGFpbiwgcmVhZF9wZGJfc2MsIAogICAgICAgICAgICAgICAgICAgcGF0aCA9IHBkYl9wYXRoLCBwcmVmaXggPSBwZGJfcHJlZml4KSkgJT4lIAogIGZpbHRlcighaXMubmEod3QpKSAgCgpkYXRhc2V0CmBgYAoKIyBHZXQgbXV0YW50cwoKIyMgSW5pdGlhbGl6ZSB3aWxkLXR5cGUKCkNoZWNrIHRoYXQgaXQgd29ya3Mgd2hlbiBwZGJfYWN0aXZlX3NpdGUgaXMgZGVmaW5lZApgYGB7cn0KcGRiX2lkIDwtIGRhdGFzZXQkcGRiCmNoYWluIDwtIGRhdGFzZXQkY2hhaW4Kd3QgPC0gcmVhZF9wZGJfc2MocGRiX2lkLCBjaGFpbiwgcGRiX3BhdGgsIHBkYl9wcmVmaXgpCmR1bW15ID0gc2FtcGxlKHd0JHBkYl9zaXRlLCAxKQpkdW1teSA9IGMoZHVtbXkgLSAxLCBkdW1teSwgZHVtbXkgKyAxKQpkdW1teQp3dCA8LSBpbml0X3Byb3Qod3QsICBwZGJfc2l0ZV9hY3RpdmUgPSBkdW1teSwgc2RfbWluID0gcGFyYW0kbXV0JHNkX21pbikKc3RyKHd0KQpgYGAKCkNoZWNrIHRoYXQgaXQgd29ya3Mgd2hlbiBwZGJfYWN0aXZlX3NpdGUgaXMgbm90IGRlZmluZWQKYGBge3J9CnBkYl9pZCA8LSBkYXRhc2V0JHBkYgpjaGFpbiA8LSBkYXRhc2V0JGNoYWluCnd0IDwtIHJlYWRfcGRiX3NjKHBkYl9pZCwgY2hhaW4sIHBkYl9wYXRoLCBwZGJfcHJlZml4KQp3dCA8LSBpbml0X3Byb3Qod3QsICBzZF9taW4gPSBwYXJhbSRtdXQkc2RfbWluKQpzdHIod3QpCmBgYAoKIyMgUGxvdCBlbm0KCgojIyMgUGxvdCBhbmQgY29tcGFyZSBtc2YKCmBgYHtyfQplbm1fbXNmX3Bsb3Qod3QsIGRfbWF4ID0gcGFyYW0kZW5tJGRfbWF4KQpgYGAKCiMjIyBQbG90IG5vcm1hbC1tb2RlIG1hdHJpeAoKYGBge3J9CmVubV9tb2Rlc19tYXRyaXhfcGxvdCh3dCkKYGBgCgojIyMgUGxvdCBhIGZldyBub3JtYWwgbW9kZXMKICAKYGBge3J9Cm5zaXRlcyA9IHd0JG5zaXRlcwpubW9kZXMgPC0gbWF4KHd0JGVubSRtb2RlKQplbm1fbW9kZXNfcGxvdCh3dCwgbW9kZXMgPSBjKDEsIDIsIDMsIDQsIG5tb2RlcyAtIDMsIG5tb2RlcyAtIDIsIG5tb2RlcyAtIDEsIG5tb2RlcykpCmBgYAogIAoKCiMjIE11dGF0aW9uYWwgY2hhbmdlIG9mIHN0cnVjdHVyZQoKIyMjIEdldCBtdXRhbnRzIHdpdGhvdXQgcmVjYWxjdWxhdGluZyBFTk0KCk5vdGUgdGhhdCBlbnRyb3B5IHRlcm1zIGRvIG5vdCBjaGFuZ2Ugdy5yLnQuIHdpbGQtdHlwZS4KCmBgYHtyfQpnZXRfbXV0X2VuZXJneSA8LSBmdW5jdGlvbihwcm90LCBzaXRlLCBtdXRhdGlvbiwgdXBkYXRlX2VubSwgYWRkX2ZydXN0KSB7CiAgbXV0IDwtIGdldF9tdXRhbnRfc2l0ZSh3dCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpdGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGlvbiwgd3QsIHd0LAogICAgICAgICAgICAgICAgICAgICAgICAgICBzZF9taW4gPSBwYXJhbSRtdXQkc2RfbWluLAogICAgICAgICAgICAgICAgICAgICAgICAgICBkbF9zaWdtYSA9IHBhcmFtJG11dCRkbF9zaWdtYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwgPSBwYXJhbSRlbm0kbW9kZWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRfbWF4ID0gcGFyYW0kZW5tJGRfbWF4LAogICAgICAgICAgICAgICAgICAgICAgICAgICB2MCA9IHBhcmFtJGVubSR2MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2ZydXN0ID0gYWRkX2ZydXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICB1cGRhdGVfZW5tID0gdXBkYXRlX2VubSkKICBhc190aWJibGUobXV0JGVuZXJneSkKfQoKZGYgPC0gdGliYmxlKHByb3QgPSBjKCJ3dCIsICJtdXRfbm9mcnVzdCIsICJtdXRfZnJ1c3QiKSwKICAgICAgICAgICAgIHNpdGUgPSByZXAoODAsIDMpLAogICAgICAgICAgICAgd3QgPSBsc3Qod3QpLAogICAgICAgICAgICAgbXV0YXRpb24gPSBjKDAsIDEsIDEpLAogICAgICAgICAgICAgdXBkYXRlX2VubSA9IGMoRiwgRiwgRiksCiAgICAgICAgICAgICBhZGRfZnJ1c3QgPSBjKEYsIEYsIFQpKSAlPiUgCiAgbXV0YXRlKG11dF9lbmVyZ3kgPSBwbWFwKGxpc3Qod3QsIHNpdGUsIG11dGF0aW9uLCB1cGRhdGVfZW5tLCBhZGRfZnJ1c3QpLCBnZXRfbXV0X2VuZXJneSkpICU+JSAKICB1bm5lc3QobXV0X2VuZXJneSkgJT4lIAogIGFycmFuZ2UobXV0YXRpb24sIGFkZF9mcnVzdCwgdXBkYXRlX2VubSkgJT4lIAogIHNlbGVjdCgtcHJvdCwgLXd0LCAtbXV0YXRpb24pIAoKZGYKCmBgYAoKCgojIyMgUGxvdCBzdHJ1Y3R1cmFsIHJlc3BvbnNlCiRmX3tpan0gPSBrX3tpan0gXGRlbHRhIGxfe2lqfSQgaXMgdGhlIGZvcmNlIGluIHRoZSBkaXJlY3Rpb24gb2YgY29udGFjdCAkaS1qJC4KJGRlID0gS157MS8yfSBkciA9IENeey0xLzJ9ZGYkLCAkZHIgPSBDIGRmJC4gCgpUaGVyZWZvcmUsIGluIG5vcm1hbC1tb2RlIHJlcHJlc2VudGF0aW9uOiAkZGVfe259ID0gXHNpZ21hX24gZGZfe259JCAgYW5kICRkcl9uID0gc2lnbWFfbl4yIGRmX24kLiAKCkJ5IGFuYWxvZ3ksIGluIHNpdGUgcmVwcmVzZW50YXRpb24sIGNoZWNrIGlmIGl0J3MgYXBwcm94aW1hdGVseSBzbyB0aGF0ICRkZV4yX3tpfSA9IFxzaWdtYV9uXjIgZGZeMl97aX0kICBhbmQgJGRyXjJfaSA9IFxzaWdtYV9uXjQgZGZeMl9pJC4gCgpSZW1lbWJlciB0aGF0IG9uIGF2ZXJhZ2UgJGRmXjJfbiBccHJvcHRvIFxmcmFjezF9e1xzaWdtYV9uXjJ9JCBhbmQgcHJvYmFibHkgJGRmXjJfaSBccHJvcHRvIDEgLyBcc2lnbWFfaV4yJC4KCiMjIyMgUmVzcG9uc2UgYWxvbmcgc2l0ZXMKYGBge3J9Cm11dCA8LSBnZXRfbXV0YW50X3NpdGUod3QsIDUwLCBtdXRhdGlvbiA9IDEpCnJlc3BvbnNlX3NpdGVfcGxvdCh3dCwgbXV0KQoKYGBgCgojIyMjIFJlc3BvbnNlIGFsb25nIG5vcm1hbCBtb2RlcwoKYGBge3J9CnJlc3BvbnNlX25tX3Bsb3Qod3QsIG11dCkKYGBgCgoKIyMjIFBlcnR1cmJhdGlvbiBSZXNwb25zZSBTY2FubmluZzogc2luZ2xlLXNpdGUgbXV0YXRpb25zCgpgYGB7cn0KIyBnZXQgbXV0YW50IHRhYmxlCm11dGF0aW9uIDwtIHNlcShmcm9tID0gMCwgdG8gPSAxMCkKaiA8LSB3dCRzaXRlCgpwcm90X3NpdGUgPC0gZnVuY3Rpb24ocHJvdCkgcHJvdCRzaXRlCnByb3RfbW9kZSA8LSBmdW5jdGlvbihwcm90KSBwcm90JGVubSRtb2RlCnByb3RfZXZhbHVlIDwtIGZ1bmN0aW9uKHByb3QpIHByb3QkZW5tJGV2YWx1ZQoKCmRmX211dGFudHMgPC0gZXhwYW5kX2dyaWQod3QgPSBsaXN0KHd0KSwgaiwgbXV0YXRpb24pICAlPiUgCiAgbXV0YXRlKG11dCA9IHBtYXAobGlzdCh3dCwgaiwgbXV0YXRpb24pLCBnZXRfbXV0YW50X3NpdGUpKSAlPiUgCiAgbXV0YXRlKGkgPSBtYXAod3QsICJzaXRlIiksCiAgICAgICAgIGRyMmlqID0gbWFwMih3dCwgbXV0LCBkcjJfc2l0ZSksCiAgICAgICAgIG1zZmkgPSBtYXAod3QsIG1zZl9wcm90KSwKICAgICAgICAgbW9kZSA9IG1hcCh3dCwgcHJvdF9tb2RlKSwKICAgICAgICAgZXZhbHVlID0gbWFwKHd0LCBwcm90X2V2YWx1ZSksCiAgICAgICAgIGRyMm5qID0gbWFwMih3dCwgbXV0LCBkcjJfbm0pKSAlPiUgCiAgc2VsZWN0KC13dCwgLW11dCkKCmRmX2ogPC0gdGliYmxlKGogPSB3dCRzaXRlLCBtc2ZqID0gbXNmX3Byb3Qod3QpKQpkZl9tdXRhbnRzIDwtIGlubmVyX2pvaW4oZGZfaiwgZGZfbXV0YW50cykgJT4lIAogIHNlbGVjdChtdXRhdGlvbiwgaiwgaSwgbXNmaiwgbXNmaSwgZXZlcnl0aGluZygpKQpkZl9tdXRhbnRzIApgYGAKCiMjIyMgU3RydWN0dXJhbCByZXNwb25zZSBhbG9uZyBzaXRlcwoKRnVsbCBtZWFuIHJlc3BvbnNlIG1hdHJpeDoKCmBgYHtyfQpkZl9wcnNfc2l0ZSA8LSBkZl9tdXRhbnRzICU+JSAKICBzZWxlY3QoaiwgbXV0YXRpb24sIGksIG1zZmosIG1zZmksIGRyMmlqKSAlPiUgCiAgdW5uZXN0KGMoaSwgbXNmaSwgZHIyaWopKQoKIyBkcjJpal9tZWFuIG1hdHJpeAoKcGlqX21lYW4gPC0gIGRmX3Byc19zaXRlICU+JSAKICBncm91cF9ieShpLCBqKSAlPiUgCiAgc3VtbWFyaXNlKGRyMmlqX21lYW4gPSBtZWFuKGRyMmlqKSwKICAgICAgICAgICAgZHIyaWpfc2QgPSBzZChkcjJpaikpICU+JSAKICBnZ3Bsb3QoYWVzKGosIGksIGZpbGwgPSBzcXJ0KGRyMmlqX21lYW4pKSkgKwogIGdlb21fdGlsZSgpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfYygpICsKICB0aGVtZV9jb3dwbG90KCkgKwogIE5VTEwgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIGdndGl0bGUoInNxcnQoZHIyaWpfbWVhbikgbWF0cml4IikKCnBpal9tZWFuCgoKI2RyMmlqIGFzeW1tZXRyeQpkZiA8LSBkZl9wcnNfc2l0ZSAlPiUgCiAgZ3JvdXBfYnkoaSwgaikgJT4lIAogIHN1bW1hcmlzZShkcjJpal9tZWFuID0gbWVhbihkcjJpaikpCgpkcjJpaiA8LSBkZiRkcjJpal9tZWFuCmRpbShkcjJpaikgPC0gYyhsZW5ndGgod3Qkc2l0ZSksIGxlbmd0aCh3dCRzaXRlKSkKc3RyKGRyMmlqKQpkcjJqaSA8LSB0KGRyMmlqKQpkZiRkcjJqaSA8LSBhcy52ZWN0b3IoZHIyamkpIAoKZGYgJT4lIAogIGZpbHRlcighKGkgPT0gaikpICU+JSAKICBnZ3Bsb3QoYWVzKGRyMmlqX21lYW4sIGRyMmppKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAuMSkgKwogIHRoZW1lX2Nvd3Bsb3QoKSArCiAgZ2VvbV9zbW9vdGgoKSArCiAgc2NhbGVfeF9sb2cxMCgpICsKICBzY2FsZV95X2xvZzEwKCkgKwogIGdndGl0bGUoImRyMmlqIGlzIG5vdCBzeW1tZXRyaWMiKQoKCiMgZHIyaWogb3ZlciBzaW5nbGUgbXV0YXRpb24gc2NhbiwgdnMuIGF2ZXJhZ2Ugb3ZlciBzZXZlcmFsIG11dGF0aW9uIHNjYW5zCmRmIDwtIGRmX3Byc19zaXRlICU+JSAKICBncm91cF9ieShpLCBqKSAlPiUgCiAgc3VtbWFyaXNlKGRyMmlqX21lYW4gPSBtZWFuKGRyMmlqKSkKCmRmIDwtIGlubmVyX2pvaW4oZGYsIGRmX3Byc19zaXRlKQoKZGYgJT4lIAogIGZpbHRlcihtdXRhdGlvbiA+IDAsIG11dGF0aW9uIDwgNSkgJT4lIAogIGdncGxvdChhZXMoZHIyaWpfbWVhbiwgZHIyaWosIGNvbG9yID0gZmFjdG9yKG11dGF0aW9uKSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAuMiwgYWxwaGEgPSAuMikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICsKICBmYWNldF93cmFwKH5tdXRhdGlvbikgKwogIHNjYWxlX3hfbG9nMTAoKSArCiAgc2NhbGVfeV9sb2cxMCgpICsKICB0aGVtZV9jb3dwbG90KCkgKwogIHBhbmVsX2JvcmRlcigpICsKICBnZ3RpdGxlKCJkcjJpaiBzaW5nbGUgc2NhbiBzaW1pbGFyIHRvIGF2ZXJhZ2Ugb3ZlciBzY2FucyIpCgojIGRyMmlqX3NkIHZzLiBkcjJpal9tZWFuIHBsb3QKCnBpaiA8LSAgZGZfcHJzX3NpdGUgJT4lIAogIGdyb3VwX2J5KGksIGopICU+JSAKICBzdW1tYXJpc2UoZHIyaWpfbWVhbiA9IG1lYW4oZHIyaWopLAogICAgICAgICAgICBkcjJpal9zZCA9IHNkKGRyMmlqKSkgJT4lIAogIGdncGxvdChhZXMoZHIyaWpfbWVhbiwgZHIyaWpfc2QpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArCiAgZ2VvbV9hYmxpbmUoKSArCiAgdGhlbWVfY293cGxvdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBjb29yZF9maXhlZCgpICsKICBOVUxMICsKICBnZ3RpdGxlKCJzZChkcjJpaikgcHJvcG9ydGlvbmFsIHRvIG1lYW4oZHIyaWopIikKCnBpagoKCgoKCgpgYGAKClJlc3BvbnNlIHByb2ZpbGUgdnMuIHNpdGU6CgpgYGB7cn0KIyBBdmVyYWdlIHJlc3BvbnNlIG9mIGVhY2ggc2l0ZQpwaV9zaXRlIDwtIGRmX3Byc19zaXRlICU+JSAKICBncm91cF9ieShpLCBtc2ZpKSAlPiUgCiAgc3VtbWFyaXNlKGRyMmlfbWVhbiA9IG1lYW4oZHIyaWopKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBnZ3Bsb3QoYWVzKGksIGRyMmlfbWVhbikpICsKICBnZW9tX2xpbmUoKSArCiAgdGhlbWVfY293cGxvdCgpICsKICBOVUxMCgpwaV9tc2YgPC0gZGZfcHJzX3NpdGUgJT4lIAogIGdyb3VwX2J5KGksIG1zZmkpICU+JSAKICBzdW1tYXJpc2UoZHIyaV9tZWFuID0gbWVhbihkcjJpaikpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGdncGxvdChhZXMobXNmaSwgZHIyaV9tZWFuKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoKSArCiAgdGhlbWVfY293cGxvdCgpICsKICBOVUxMCgpwaV9ybXNmIDwtIGRmX3Byc19zaXRlICU+JSAKICBncm91cF9ieShpLCBtc2ZpKSAlPiUgCiAgc3VtbWFyaXNlKGRyMmlfbWVhbiA9IG1lYW4oZHIyaWopKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBnZ3Bsb3QoYWVzKDEgLyBtc2ZpLCBkcjJpX21lYW4pKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aCgpICsKICB0aGVtZV9jb3dwbG90KCkgKwogIE5VTEwKCgpwbG90X2dyaWQocGlfc2l0ZSwgcGxvdF9ncmlkKHBpX21zZiwgcGlfcm1zZiksIG5jb2wgPSAxKQoKCmBgYAoKSW5mbHVlbmNlIHByb2ZpbGUgKGRyMmlqIGF2ZXJhZ2VkIG92ZXIgaSk6CgpgYGB7cn0KIyBBdmVyYWdlIHJlc3BvbnNlIG9mIGVhY2ggc2l0ZQpwal9zaXRlIDwtIGRmX3Byc19zaXRlICU+JSAKICBncm91cF9ieShqLCBtc2ZqKSAlPiUgCiAgc3VtbWFyaXNlKGRyMmpfbWVhbiA9IG1lYW4oZHIyaWopKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBnZ3Bsb3QoYWVzKGosIGRyMmpfbWVhbikpICsKICBnZW9tX2xpbmUoKSArCiAgdGhlbWVfY293cGxvdCgpICsKICBOVUxMCgpwal9tc2YgPC0gZGZfcHJzX3NpdGUgJT4lIAogIGdyb3VwX2J5KGosIG1zZmopICU+JSAKICBzdW1tYXJpc2UoZHIyal9tZWFuID0gbWVhbihkcjJpaikpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGdncGxvdChhZXMobXNmaiwgZHIyal9tZWFuKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoKSArCiAgdGhlbWVfY293cGxvdCgpICsKICBOVUxMCgpwal9ybXNmIDwtIGRmX3Byc19zaXRlICU+JSAKICBncm91cF9ieShqLCBtc2ZqKSAlPiUgCiAgc3VtbWFyaXNlKGRyMmpfbWVhbiA9IG1lYW4oZHIyaWopKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBnZ3Bsb3QoYWVzKDEgLyBtc2ZqLCBkcjJqX21lYW4pKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aCgpICsKICB0aGVtZV9jb3dwbG90KCkgKwogIE5VTEwKCgoKcGxvdF9ncmlkKHBqX3NpdGUsIHBsb3RfZ3JpZChwal9tc2YsIHBqX3Jtc2YpLCBuY29sID0gMSkKCgpgYGAKCiMjIyMgU3RydWN0dXJhbCByZXNwb25zZSBhbG9uZyBub3JtYWwgbW9kZXMKCmBgYHtyfQpkZl9wcnNfc2l0ZSA8LSBkZl9tdXRhbnRzICU+JSAKICBzZWxlY3QoaiwgbXV0YXRpb24sIGksIGRyMmkpICU+JSAKICByZW5hbWUoZHIyID0gZHIyaSkgJT4lIAogIHVubmVzdChpLCBkcjIpIAoKcGlqID0gZGZfcHJzX3NpdGUgJT4lIAogIGdyb3VwX2J5KGksIGopICU+JSAKICBzdW1tYXJpc2UoZHIyX21lYW4gPSBtZWFuKGRyMiksCiAgICAgICAgICAgIGRyMl9zZCA9IHNkKGRyMikpICU+JSAKICBnZ3Bsb3QoYWVzKGksIGosIGZpbGwgPSBzcXJ0KGRyMl9tZWFuKSkpICsKICBnZW9tX3RpbGUoKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKCkgKwogIHRoZW1lX2Nvd3Bsb3QoKQoKcGkgPC0gZGZfcHJzX3NpdGUgJT4lIAogIGdyb3VwX2J5KGkpICU+JSAKICBzdW1tYXJpc2UoZHIyX21lYW4gPSBtZWFuKGRyMiksCiAgICAgICAgICAgIGRyMl9zZCA9IHNkKGRyMikpICU+JSAKICBnZ3Bsb3QoYWVzKGksIGRyMl9tZWFuKSkgKwogIGdlb21fbGluZSgpICsKICB0aGVtZV9jb3dwbG90KCkKCnBqIDwtIGRmX3Byc19zaXRlICU+JSAKICBncm91cF9ieShqKSAlPiUgCiAgc3VtbWFyaXNlKGRyMl9tZWFuID0gbWVhbihkcjIpLAogICAgICAgICAgICBkcjJfc2QgPSBzZChkcjIpKSAlPiUgCiAgZ2dwbG90KGFlcyhqLCBkcjJfbWVhbikpICsKICBnZW9tX2xpbmUoKSArCiAgdGhlbWVfY293cGxvdCgpCgpwbG90X2dyaWQocGlqLCBwbG90X2dyaWQocGksIHBqKSwgbmNvbCA9IDEpCmBgYAoKIyMgTXV0YXRpb25hbCBjaGFuZ2Ugb2YgRU5NIAoKIyMjIEdldCBtdXRhbnRzIHJlY2FsY3VsYXRpbmcgRU5NCgpOb3cgZW50cm9weSB0ZXJtcyBzaG91bGQgY2hhbmdlLgoKYGBge3J9CmdldF9tdXRfZW5lcmd5IDwtIGZ1bmN0aW9uKHByb3QsIHNpdGUsIG11dGF0aW9uLCB1cGRhdGVfZW5tLCBhZGRfZnJ1c3QpIHsKICBtdXQgPC0gZ2V0X211dGFudF9zaXRlKHd0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l0ZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0aW9uLCB3dCwgd3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNkX21pbiA9IHBhcmFtJG11dCRzZF9taW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRsX3NpZ21hID0gcGFyYW0kbXV0JGRsX3NpZ21hLAogICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbCA9IHBhcmFtJGVubSRtb2RlbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZF9tYXggPSBwYXJhbSRlbm0kZF9tYXgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHYwID0gcGFyYW0kZW5tJHYwLAogICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfZnJ1c3QgPSBhZGRfZnJ1c3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwZGF0ZV9lbm0gPSB1cGRhdGVfZW5tKQogIGFzX3RpYmJsZShtdXQkZW5lcmd5KQp9CgpkZiA8LSB0aWJibGUocHJvdCA9IGMoInd0IiwgIm11dGZmIiwgIm11dGZ0IiwgIm11dHRmIiwgIm11dHR0IiksCiAgICAgICAgICAgICBzaXRlID0gcmVwKDgwLCA1KSwKICAgICAgICAgICAgIHd0ID0gbHN0KHd0KSwKICAgICAgICAgICAgIG11dGF0aW9uID0gYygwLCAxLCAxLCAxLCAxKSwKICAgICAgICAgICAgIHVwZGF0ZV9lbm0gPSBjKEYsIEYsIEYsIFQsIFQpLAogICAgICAgICAgICAgYWRkX2ZydXN0ID0gYyhGLCBGLCBULCBGLCBUKSkgJT4lIAogIG11dGF0ZShtdXRfZW5lcmd5ID0gcG1hcChsaXN0KHd0LCBzaXRlLCBtdXRhdGlvbiwgdXBkYXRlX2VubSwgYWRkX2ZydXN0KSwgZ2V0X211dF9lbmVyZ3kpKSAlPiUgCiAgdW5uZXN0KG11dF9lbmVyZ3kpICU+JSAKICBhcnJhbmdlKG11dGF0aW9uLCBhZGRfZnJ1c3QsIHVwZGF0ZV9lbm0pICU+JSAKICBzZWxlY3QoLXByb3QsIC13dCwgLW11dGF0aW9uKSAKCmRmCgpgYGAKCmBgYHtyfQogIGdldF9tdXQgPC1mdW5jdGlvbih3dCwgc2l0ZSwgbXV0YXRpb24gPSAxLCBkbF9zaWdtYSA9IDEpIHsKICAgIGdldF9tdXRhbnRfc2l0ZSh3dCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpdGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGlvbiwgd3QsIHd0LAogICAgICAgICAgICAgICAgICAgICAgICAgICBzZF9taW4gPSBwYXJhbSRtdXQkc2RfbWluLAogICAgICAgICAgICAgICAgICAgICAgICAgICBkbF9zaWdtYSA9IGRsX3NpZ21hLAogICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbCA9IHBhcmFtJGVubSRtb2RlbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZF9tYXggPSBwYXJhbSRlbm0kZF9tYXgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHYwID0gcGFyYW0kZW5tJHYwLAogICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfZnJ1c3QgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICB1cGRhdGVfZW5tID0gVCkKICB9IAoKbXV0IDwtIGdldF9tdXQod3QsIDg3KQoKbXNmX3d0IDwtIG1zZl9wcm90KHd0KQptc2ZfbXV0IDwtIG1zZl9wcm90KG11dCkKbXNmX3d0CgpkZiA8LSB0aWJibGUoc2l0ZSA9IHd0JHNpdGUsIHd0X21zZiA9IG1zZl93dCwgbXV0X21zZiA9IG1zZl9tdXQpIAoKZGYgJT4lIAogIG11dGF0ZShtaW5fbXNmID0gbWFwMl9kYmwod3RfbXNmLCBtdXRfbXNmLCBtaW4pLAogICAgICAgICBtYXhfbXNmID0gbWFwMl9kYmwod3RfbXNmLCBtdXRfbXNmLCBtYXgpKSAlPiUgCiAgbXV0YXRlKG1pbl9tc2YgPSB3dF9tc2YsCiAgICAgICAgIG1heF9tc2YgPSBtdXRfbXNmKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKCJ3dF9tc2YiLCAibXV0X21zZiIpLAogICAgICAgICAgICAgICBuYW1lc190byA9ICJwcm90ZWluIiwKICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIm1zZiIpICU+JSAKICBnZ3Bsb3QoYWVzKHNpdGUsIG1zZiwgY29sb3IgPSBwcm90ZWluKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3JpYmJvbihhZXMoeW1pbiA9IG1pbl9tc2YsIHltYXggPSBtYXhfbXNmKSwgYWxwaGEgPSAxLCBjb2xvciA9IE5BLCBmaWxsID0gInBpbmsiKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKCkgKwogIHRoZW1lX2Nvd3Bsb3QoKSArCiAgTlVMTAoKZGYgJT4lIAogIGdncGxvdChhZXMoc2l0ZSwgKG1zZl9tdXQgLSBtc2Zfd3QpL21zZl93dCkpICsKICBnZW9tX2xpbmUoKSArCiAgdGhlbWVfY293cGxvdCgpCgoKYGBgCgoKCgoKCmBgYHtyLCBldmFsID0gRkFMU0V9CmdldF9tdXRfZW5lcmd5IDwtIGZ1bmN0aW9uKHNpdGUsIG11dGF0aW9uLCB3dCwuLi4pIHsKICAjIGdldHMgbXV0YW50LCByZXR1cm5zIG9ubHkgaXRzIGVuZXJneSB0ZXJtcwogIG11dCA8LSBnZXRfbXV0YW50X3NpdGUod3QsIHNpdGUsIG11dGF0aW9uLC4uLiApCiAgbXV0JGVuZXJneQp9CgojIHNldCB1cCBzaXRlLW11dGFudCB0YWJsZQogIHNwbV90YmwgPC0gc3BtX3RibCAlPiUgCiAgICB1bm5lc3Qoc2l0ZSwgcGRiX3NpdGUsIGNuLCB3Y24sIGJmYWN0b3IsIGJmYWN0b3JfZW5tLCBkX2FjdGl2ZSwgLmRyb3AgPSBUUlVFKSAlPiUKICAgIG11dGF0ZShtdXRhdGlvbiA9IHJlcGxpY2F0ZShuKCksIGMoMDpubXV0X3Blcl9zaXRlKSwgc2ltcGxpZnkgPSBGQUxTRSkpICU+JQogICAgdW5uZXN0KG11dGF0aW9uLCAuZHJvcCA9IFRSVUUpCiAgCiAgIyBnZXQgbXV0YW50cwogIHNwbV90YmwgPC0gc3BtX3RibCAlPiUgCiAgICBtdXRhdGUoIAogICAgICB3dF9lbmVyZ3kgPSBtYXAoc2l0ZSwgfiB3dF9lbmVyZ3kpLAogICAgICBtdXRfZW5lcmd5ID0gbWFwMihzaXRlLCBtdXRhdGlvbiwgZ2V0X211dF9lbmVyZ3ksICAKICAgICAgICAgICAgICAgICAgICAgICAgd3QgPSB3dCwgCiAgICAgICAgICAgICAgICAgICAgICAgIHNkX21pbiA9IHBhcmFtJG11dCRzZF9taW4sCiAgICAgICAgICAgICAgICAgICAgICAgIHVwZGF0ZV9lbm0gPSB1cGRhdGVfZW5tLCAKICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2ZydXN0ID0gYWRkX2ZydXN0KSkgCiAgCiAgIyBwcmVwYXJlIGZvciBvdXRwdXQKICBzcG1fdGJsIDwtIHNwbV90YmwgJT4lIAogICAgcmVuYW1lKHd0ID0gd3RfZW5lcmd5LCBtdXQgPSBtdXRfZW5lcmd5KSAlPiUgCiAgICBtdXRhdGUod3QgPSBtYXAod3QsIGFzX3RpYmJsZSksIAogICAgICAgICAgIG11dCA9IG1hcChtdXQsIGFzX3RpYmJsZSkpICU+JSAKICAgIHVubmVzdCh3dCwgbXV0LCAuc2VwID0gIl8iKSAKICAKICAjIG91dHB1dAogIHBkYiA8LSBzcG1fdGJsJHBkYltbMV1dCiAgY2hhaW4gPC0gc3BtX3RibCRjaGFpbltbMV1dCiAgb3V0X2ZpbGUgPC0gZmlsZS5wYXRoKHJ1bl9wYXRoLHBhc3RlMCgic3BtXyIscGRiLCAiXyIsIGNoYWluLCAiLmNzdi5neiIpKQogIHdyaXRlLmNzdihzcG1fdGJsLCBmaWxlID0gZ3pmaWxlKG91dF9maWxlKSxyb3cubmFtZXMgPSBGQUxTRSkKCmBgYAoK